/******************************************************************************/
/* PODSTAWY GRAFIKI KOMPUTEROWEJ - Laboratorium Komputerowe nr 7              */
/* Graficzna prezentacja danych                              J. Tarasiuk 2008 */
/******************************************************************************/

// UWAGA: TO JEST JEDYNY PLIK, KTORY NALEZY EDYTOWAC **************************

#include <wx/dcclient.h>
#include <wx/dcmemory.h>
#include "Main_Frm.h"

void DrawPoint(float x, float y, unsigned char *data, bool i = false) {
    if(x>-2.5 && x<2.5 && y>-2.5 && y<2.5) {
        if(!i) {
            data[(int)((100*(x+2.5)+50000*(-y+2.5))*3)] = 0;
            data[(int)((100*(x+2.5)+50000*(-y+2.5))*3)+1] = 0;
            data[(int)((100*(x+2.5)+50000*(-y+2.5))*3)+2] = 0;
        } else {
            data[(int)((50000*(x+2.5)+100*(-y+2.5))*3)] = 0;
            data[(int)((50000*(x+2.5)+100*(-y+2.5))*3)+1] = 0;
            data[(int)((50000*(x+2.5)+100*(-y+2.5))*3)+2] = 0;
        }
    }
}

float FindPoint(float w1, float w2, float lev, float p1, float p2) {
    if (w2>w1) {
         if (lev>w2 || lev<w1) {
            return (-2.5);
         }
         else {
            return (p1+(p2-p1)*(lev-w1)/(w2-w1));
         }
    }
     if (w2<w1) {
         if (lev<w2 || lev>w1) {
            return (-2.5);
         }
        else {
            return (p2+(p1-p2)*(lev-w2)/(w1-w2));
        }
     }
     if (w1==lev) {
        return (p1);
     }
     else {
        return (-2.5);
     }
}

// Na pewno przyda sie jakas funkcja pomocnicza rysujaca kontury
void DrawContour(float p[4][2], float w[4], float lev, unsigned char *data)
{
    float d[4];
    d[0]=FindPoint(w[0],w[1],lev,p[0][1],p[1][1]);
    d[1]=FindPoint(w[1],w[2],lev,p[1][0],p[2][0]);
    d[2]=FindPoint(w[2],w[3],lev,p[2][1],p[3][1]);
    d[3]=FindPoint(w[3],w[0],lev,p[3][0],p[0][0]);
    if (d[0]>=-2.5) {
        //DrawPoint(d[0],p[0][0],data,true);
        //DrawPoint(p[0][0],d[0],data);
        if (d[1]>=-2.5)
            DrawPoint(d[1],p[1][1],data);
        else if (d[2]>-2.5)
            DrawPoint(p[2][0],d[2],data);
        else if (d[3]>-2.5)
            DrawPoint(d[3],p[3][1],data);
    }
    else
    if (d[1]>=-2.5) {
    DrawPoint(d[1],p[1][1],data);
    if (d[2]>=-2.5)
        DrawPoint(p[2][0],d[2],data);
    else if (d[3]>=-2.5)
        DrawPoint(d[3],p[3][1],data);
    }
    else
    if (d[2]>=-2.5){
        DrawPoint(p[2][0],d[2],data);
    if (d[3]>=-2.5)
        DrawPoint(d[3],p[3][1],data);
    }
}

// Na pewno potrzebna bedzie funkcja wykonujaca interpolacje Sheparda
static float Shepard(int N, float d[100][3], float x, float y)
{
    float f,h,wf=0,hj=0;

        for (int i=0;i<N;i++) {
        if(d[i][0] != x && d[i][1] != y) {
                h = (x-d[i][0])*(x-d[i][0]) + (y-d[i][1])*(y-d[i][1]);
                wf += (1/h)*d[i][2];
                    hj += 1/h;
        }
        }

        f = wf/hj;

        return f;

}

void MinMax(int N, float d[100][3], float &min, float &max) {
    min = max = 0;
    for (int i=0;i<N;i++) {
        min = (d[i][2] < min) ? d[i][2] : min;
        max = (d[i][2] > max) ? d[i][2] : max;
    }
}

void Main_Frm::DrawMap(int N, float d[100][3], bool Contour, int MappingType, int NoLevels, bool ShowPoints)
{
    wxMemoryDC memDC;
	tmpImg = wxImage(500,500);
    memDC.SelectObject(MemoryBitmap);
    memDC.Clear();
    memDC.SetDeviceOrigin(250,250);

    float s = 100;
    float min,max,delta;

    MinMax(N,d,min,max);
    delta = max - min;

    unsigned char *data;
    int w,h;

    w = tmpImg.GetWidth();
    h = tmpImg.GetHeight();
    data = tmpImg.GetData();

    for (int i=0;i<w*h*3;i++) {
        data[i] = 255;
    }

    float levels[9];
    for (int i=0;i<NoLevels;i++) {
        levels[i] = min + (i+1)*delta/(float)(NoLevels+1);
    }

    if (MappingType) {
        for (float i= -2.5;i<2.5;i+=0.01) {
            for (float j= -2.5;j<2.5;j+=0.01) {
                float f = Shepard(N,d,i,j);
                int r,g,b;
                r = (int)((100*(i+2.5)+50000*(-j+2.5))*3);
                g = r+1;
                b = r+2;
                switch(MappingType) {
                    case 1:
                        int r,g,b;
                        data[r] = (int)(255*(1-(f-min)/delta));
                        data[g] = 0;
                        data[b] = (int)(255*(f-min)/delta);
                    break;
                    case 2:
                        int tc;
                        if (f > min+delta/2.0) {
                            data[r] = 0;
                            tc = (int)(255.0*(1-2.0*(f-min-delta/2.0)/delta));
                            data[g] = tc < 0 ? 0 : tc;
                            tc = (int)(255.0*2.0*(f-min-delta/2.0)/delta);
                            data[b] = tc > 255 ? 255 : tc;
                        } else {
                            tc = (int)(255.0*(1-2.0*(f-min)/delta));
                            data[r] = tc < 0 ? 0 : tc;
                            tc = (int)(255.0*2.0*(f-min)/delta);
                            data[g] = tc > 255 ? 255 : tc;
                            data[b] = 0;
                        }
                    break;
                    case 3:
                        data[r] = (int)(255*(f-min)/delta);
                        data[g] = (int)(255*(f-min)/delta);
                        data[b] = (int)(255*(f-min)/delta);
                    break;
                }
            }
        }
    }
    if (Contour) {
        float p[4][2];
        float w[4];
        for (float i=-2.5;i<2.5;i+=0.01) {
            for (float j=-2.5;j<2.5;j+=0.01) {
                p[0][0]=i; p[0][1]=j;
                p[1][0]=i; p[1][1]=(j+0.01);
                p[2][0]=(i+0.01); p[2][1]=(j+0.01);
                p[3][0]=(i+0.01); p[3][1]=j;
                w[0]=Shepard(N,d,i,j);
                w[1]=Shepard(N,d,i,j+0.01);
                w[2]=Shepard(N,d,i+0.01,j+0.01);
                w[3]=Shepard(N,d,i+0.01,j);
                for (int k=0;k<NoLevels;k++) {
                    DrawContour(p,w,levels[k],data);
                }
            }
        }
    }
    MemoryBitmap = wxBitmap(tmpImg);
    //memDC.DrawBitmap(tmpImg, -250, -250, true);
    if (ShowPoints) {
        memDC.SetPen(wxPen(wxColour(0,0,0)));
        int size = 3;
        for (int i=0;i<N;i++) {
            memDC.DrawLine(s*d[i][0]-size,-s*d[i][1],s*d[i][0]+size,-s*d[i][1]);
            memDC.DrawLine(s*d[i][0],-s*d[i][1]-size,s*d[i][0],-s*d[i][1]+size);
        }
    }

}
